package com.kipling.kio.server;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.kipling.kio.core.bean.MsgBean;
import com.kipling.kio.core.intf.Packet;

/** 
 * @author KiplingLee E-mail: kiplinglee@163.com
 * @version 创建时间：2017年5月3日 下午5:02:21 
 * 
 */
public class KioServer< P extends Packet, R> {	
	
	private static Logger log = LoggerFactory.getLogger(KioServer.class);
	
	private ServerGroupContext< P, R> serverGroupContext;

	private boolean isWaitingStop = false;
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}
	
	/**
	 * 
	 * @param serverGroupContext
	 *
	 * @author: tanyaowu
	 * 2017年1月2日 下午5:53:06
	 *
	 */
	public KioServer(ServerGroupContext< P, R> serverGroupContext)
	{
		super();
		this.serverGroupContext = serverGroupContext;
	}

	/**
	 * @return the serverGroupContext
	 */
	public ServerGroupContext< P, R> getServerGroupContext()
	{
		return serverGroupContext;
	}
	
	/**
	 * @param serverGroupContext the serverGroupContext to set
	 */
	public void setServerGroupContext(ServerGroupContext< P, R> serverGroupContext)
	{
		this.serverGroupContext = serverGroupContext;
	}
	
	public void start(String serverIp, int serverPort) throws IOException
	{
		ExecutorService groupExecutor = serverGroupContext.getGroupExecutor();
		
		//服务器通道
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        
        //注册器
        Selector selector = Selector.open();
        //网络端口
        SocketAddress socketAddress = new InetSocketAddress(serverIp,serverPort);      
        serverSocketChannel.socket().bind(socketAddress);
        serverSocketChannel.configureBlocking(false);//异步
        //注册,返回感兴趣的selectionKey对象
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);//这里SelectionKey.OP_ACCEPT也可以
        
        while (!groupExecutor.isShutdown()){
        	 //准备就绪的通道
            int selectCount = selector.select();
            if (selectCount == 0) {
                continue;
            }else{
            	Set<SelectionKey> selectionKeySet = selector.selectedKeys();
				for (final SelectionKey selectionKey : selectionKeySet) {
					if (selectionKey.isValid() && selectionKey.isAcceptable()) {
						// 返回和客户端通信的对象
						SocketChannel socketChannel = ((ServerSocketChannel) selectionKey.channel()).accept();
						socketChannel.configureBlocking(false);
						// 和客户端通信对象注册可读事件
						socketChannel.register(selector, SelectionKey.OP_READ);
					} else if (selectionKey.isValid() && selectionKey.isReadable()) {
						SocketChannel socketChannel = (SocketChannel) selectionKey.channel();						
						ByteBuffer byteBuffer = ByteBuffer.allocate(2048);
						
						int count = -1;
						try{
							count = socketChannel.read(byteBuffer);
						}catch(IOException e){
							log.error("",e);
						}
			        	if (count == -1) {
			        		socketChannel.close();
			        	}else{
			        		MsgBean bean = new MsgBean();
							byteBuffer.flip();
							bean.setByteBuffer(byteBuffer);
							bean.setSocketChannel(socketChannel);
			        		serverGroupContext.getSocketChannelHandle().put(bean);
			        	}
					}
					// 移除已经处理完的selectionKey
					selectionKeySet.remove(selectionKey);

				}
            }
        }
	}
	
	public boolean stop()
	{
		isWaitingStop = true;
		boolean ret = true;
		ExecutorService groupExecutor = serverGroupContext.getGroupExecutor();
		groupExecutor.shutdown();
		serverGroupContext.setStopped(true);
		try
		{
			ret = ret && groupExecutor.awaitTermination(6000, TimeUnit.SECONDS);
		} catch (InterruptedException e)
		{
			log.error(e.getLocalizedMessage(), e);
		}		
		return ret;
	}

	public boolean isWaitingStop() {
		return isWaitingStop;
	}

	public void setWaitingStop(boolean isWaitingStop) {
		this.isWaitingStop = isWaitingStop;
	}
	
	
	

}
